package com.mine.modules.vm.service.impl;

import cn.hutool.core.map.MapUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.toolkit.Db;
import com.mine.common.utils.AnnotationUtil;
import com.mine.common.utils.CollUtils;
import com.mine.common.utils.ToTreeUtil;
import com.mine.modules.vm.common.constant.BizConstant;
import com.mine.modules.vm.domain.dto.CommonElementListDto;
import com.mine.modules.vm.domain.dto.QueryElementDto;
import com.mine.modules.vm.domain.query.MonitorPageQuery;
import com.mine.modules.vm.domain.query.MonitorPreviewURLsQuery;
import com.mine.modules.vm.common.utils.MonitorUtil;
import com.mine.common.utils.UuidUtil;
import com.mine.common.domain.vo.Result;
import com.mine.modules.vm.entity.*;
import com.mine.modules.vm.mapper.VmMonitorMapper;
import com.mine.modules.vm.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 监控设备 服务实现类
 * </p>
 *
 * @author xujf
 * @since 2024-09-22
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class VmMonitorServiceImpl extends ServiceImpl<VmMonitorMapper, VmMonitor> implements IVmMonitorService, IVmBaseService {

    private final IVmMonitorRegionsService monitorRegionsService;

    private final IVmLayerService vmLayerService;

    private final IVmLayerElementService layerElementService;

    private final VmMonitorMapper vmMonitorMapper;

    @Override
    public Result<?> queryPageList(MonitorPageQuery monitorPageQuery) {
        LambdaQueryWrapper<VmMonitor> wrapper = new LambdaQueryWrapper<>();
        wrapper.and(StringUtils.isNotBlank(monitorPageQuery.getKeywords()), e ->
                e.like(VmMonitor::getCameraName, monitorPageQuery.getKeywords())
                        .or()
                        .like(VmMonitor::getCameraIndexCode, monitorPageQuery.getKeywords())
        );
        Page<VmMonitor> page = new Page<>(monitorPageQuery.getPageNo(), monitorPageQuery.getPageSize());
        if (StringUtils.isNotBlank(monitorPageQuery.getLayerId())) {
            List<String> layerIds = vmLayerService.getAllSubIdsByParentId(monitorPageQuery.getLayerId());
            IPage<VmMonitor> pageList = vmMonitorMapper.selectPageWithElement(page, layerIds, monitorPageQuery.getKeywords(), monitorPageQuery.getTreeIndexCode());
            return Result.ok(pageList);
        } else {
            wrapper.in(StringUtils.isNotBlank(monitorPageQuery.getTreeIndexCode()), VmMonitor::getRegionIndexCode, monitorPageQuery.getTreeIndexCode());
            IPage<VmMonitor> pageList = this.page(page, wrapper);
            return Result.ok(pageList);
        }
    }

    @Override
    public Result<?> treeAllList() {
        try {
            LambdaQueryWrapper<VmMonitorRegions> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.orderByDesc(VmMonitorRegions::getIndexCode);
            List<VmMonitorRegions> list = this.monitorRegionsService.list(queryWrapper);
            List<VmMonitorRegions> treeList = new ArrayList<>();
            ToTreeUtil.getTreeList(treeList, list, null);
            return Result.OK("查询成功！", treeList);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return Result.error(e.getMessage());
        }
    }

    @Override
    public Result<String> getPreviewURLs(MonitorPreviewURLsQuery previewURLsQuery) {
        try {
            Map<String, Object> params = new HashMap<String, Object>();
            params.put("cameraIndexCode", previewURLsQuery.getCameraIndexCode());
            params.put("streamType", Integer.parseInt(previewURLsQuery.getStreamType()));
            params.put("protocol", previewURLsQuery.getProtocol());
            params.put("transmode", Integer.parseInt(previewURLsQuery.getTransmode()));
            String cameras = MonitorUtil.previewURLs(params);
            if (StringUtils.isNotEmpty(cameras)) {
                JSONObject object = JSONObject.parseObject(cameras);
                if (object.getString("code").equals("0")) {
                    JSONObject data = JSONObject.parseObject(object.getString("data"));
                    if (data != null) {
                        return Result.OK("取流成功", data.getString("url"));
                    } else {
                        return Result.error("获取监控点预览取流URLv2接口无数据返回");
                    }
                } else {
                    return Result.error("获取监控点预览取流URLv2接口无数据返回");
                }
            } else {
                return Result.error("获取监控点预览取流URLv2接口无数据返回");
            }
        } catch (Exception e) {
            return Result.error("获取监控点预览取流URLv2异常");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void synCameras() {
        try {
            boolean isEnd = false;
            int pageNo = 0;
            int total = 0;
            long start = System.currentTimeMillis();
            List<String> indexCodeList = new ArrayList<String>();
            while (!isEnd) {
                pageNo++;
                int pageSize = 1000;
                Map<String, Object> params = new HashMap<String, Object>();
                params.put("pageNo", pageNo);
                params.put("pageSize", pageSize);
                String cameras = MonitorUtil.cameras(params);
                if (StringUtils.isNotEmpty(cameras)) {
                    JSONObject object = JSONObject.parseObject(cameras);
                    if (object.getString("code").equals("0")) {
                        JSONObject data = JSONObject.parseObject(object.getString("data"));
                        if (data != null) {
                            total = data.getIntValue("total");
                            JSONArray list = JSONObject.parseArray(data.getString("list"));
                            if (list != null && !list.isEmpty()) {
                                for (Object obj : list) {
                                    JSONObject result = JSONObject.parseObject(obj.toString());
                                    indexCodeList.add(result.getString("cameraIndexCode"));
                                    String cameraName = result.getString("cameraName");
                                    String cameraIndexCode = result.getString("cameraIndexCode");
                                    String regionIndexCode = result.getString("regionIndexCode");
                                    if (StringUtils.isNotEmpty(cameraName) && StringUtils.isNotEmpty(cameraIndexCode) && StringUtils.isNotEmpty(regionIndexCode)) {
                                        VmMonitor vmMonitor = this.lambdaQuery().eq(VmMonitor::getCameraIndexCode, cameraIndexCode).one();
                                        if (vmMonitor == null) {
                                            vmMonitor = new VmMonitor();
                                            vmMonitor.setId(UuidUtil.getUUID());
                                            vmMonitor.setCreateTime(new Date(System.currentTimeMillis()));
                                            vmMonitor.setCameraIndexCode(cameraIndexCode);
                                            this.save(vmMonitor);
                                        }
                                        vmMonitor.setCameraName(result.getString("cameraName"));
                                        vmMonitor.setCameraType(result.getString("cameraType"));
                                        vmMonitor.setCameraTypeName(result.getString("cameraTypeName"));
                                        vmMonitor.setEncodeDevIndexCode(result.getString("encodeDevIndexCode"));
                                        vmMonitor.setEncodeDevResourceType(result.getString("encodeDevResourceType"));
                                        vmMonitor.setEncodeDevResourceTypeName(result.getString("encodeDevResourceTypeName"));
                                        vmMonitor.setGbIndexCode(result.getString("gbIndexCode"));
                                        vmMonitor.setInstallLocation(result.getString("installLocation"));
                                        vmMonitor.setLatitude(result.getString("latitude"));
                                        vmMonitor.setLongitude(result.getString("longitude"));
                                        vmMonitor.setRecordLocation(result.getString("recordLocation"));
                                        vmMonitor.setRecordLocationName(result.getString("recordLocationName"));
                                        vmMonitor.setRegionIndexCode(result.getString("regionIndexCode"));
                                        vmMonitor.setStatusName(result.getString("statusName"));
                                        vmMonitor.setUpdateTime(new Date(System.currentTimeMillis()));
                                        this.updateById(vmMonitor);
                                    }
                                }
                            } else {
                                isEnd = true;
                            }
                        } else {
                            isEnd = true;
                            log.error("分页获取监控点资源接口无数据返回");
                        }
                    } else {
                        isEnd = true;
                        log.error("分页获取监控点资源接口无数据返回");
                    }
                } else {
                    isEnd = true;
                    log.error("分页获取监控点资源接口无数据返回");
                }
            }
            //删除数据
            if (!indexCodeList.isEmpty()) {
                LambdaQueryWrapper<VmMonitor> srcQuery = new LambdaQueryWrapper<VmMonitor>();
                srcQuery.notIn(VmMonitor::getCameraIndexCode, indexCodeList);
                this.remove(srcQuery);
                //已经绑定的视频监控
                Db.lambdaUpdate(VmLayerElement.class).eq(VmLayerElement::getElementType, BizConstant.SCENE_ELEMENT_TYPE_MONITOR).notIn(VmLayerElement::getElementCode, indexCodeList).remove();
            }
            log.info("======同步【海康分页获取监控点资源接口】=====数据量:【{}】条;耗时：【{}】毫秒", total, System.currentTimeMillis() - start);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("分页获取监控点资源异常【{}】", e.getMessage());
        }
    }

    @Override
    public Result<?> countMonitorByLayerId(String layerId) {
        if (StringUtils.isBlank(layerId)) {
            return Result.error("参数不完整！");
        }
        return Result.ok(this.countByLayerId(layerId));
    }

    @Override
    public Result<?> countMonitorOfRegionByLayerId(String layerId) {
        List<Object> res = new ArrayList<>();
        VmLayer root = this.vmLayerService.getById(layerId);
        if(root == null){
            return Result.error("数据不存在！");
        }
        List<VmLayer> regions = this.vmLayerService.lambdaQuery().eq(VmLayer::getParentId, layerId).list();
        if (regions.isEmpty()) {
            Map<String, Object> obj = new HashMap<>();
            obj.put("layerId", root.getId());
            obj.put("layerName", root.getLayerName());
            obj.put("total", this.countByLayerId(root.getId()));
            res.add(obj);
        }else{
            for (VmLayer region : regions) {
                Map<String, Object> obj = new HashMap<>();
                obj.put("layerId", region.getId());
                obj.put("layerName", region.getLayerName());
                obj.put("total", this.countByLayerId(region.getId()));
                res.add(obj);
            }
        }
        return Result.ok(res);
    }

    @Override
    public Result<?> bindSceneLayerOfMonitor(String monitorId, String sceneLayerId) {
        if (StringUtils.isEmpty(monitorId)) {
            return Result.error("参数不完整！");
        }
        VmMonitor vmMonitor = this.getById(monitorId);
        if (vmMonitor == null) {
            return Result.error("监控设备不存在！");
        }
        vmMonitor.setSceneLayerId(sceneLayerId);
        this.updateById(vmMonitor);
        return Result.ok("操作成功！");
    }

    @Override
    public Result<?> getDetailsBySceneLayerId(String sceneLayerId) {
        if(StringUtils.isBlank(sceneLayerId)){
            return  Result.error("参数必填！");
        }
        VmLayerElement vmLayerElement = layerElementService.lambdaQuery()
                .eq(VmLayerElement::getSceneLayerId, sceneLayerId)
                .eq(VmLayerElement::getElementType, BizConstant.SCENE_ELEMENT_TYPE_MONITOR)
                .last(" limit 1 ")
                .one();
        if(vmLayerElement == null){
            return Result.error("数据不存在！");
        }
        VmMonitor vmMonitor = this.getById(vmLayerElement.getElementId());
        if (vmMonitor == null) {
            return Result.error("数据不存在！");
        }
        return Result.ok(vmMonitor);
    }

    private long countByLayerId(String layerId) {
        List<String> layerIds = vmLayerService.getAllSubIdsByParentId(layerId);
        List<String> elementIds = this.layerElementService.lambdaQuery().in(VmLayerElement::getLayerId, layerIds).list().stream().map(VmLayerElement::getElementId).collect(Collectors.toList());
        if (elementIds.isEmpty()) {
            return 0L;
        }
        return this.lambdaQuery().in(VmMonitor::getId, elementIds).count();
    }

    @Override
    public Object basePageList(CommonElementListDto commonElementListDto) {
        QueryWrapper<VmMonitor> queryWrapper = new QueryWrapper<>();
        if (StringUtils.isNotBlank(commonElementListDto.getKeywords())) {
            queryWrapper = AnnotationUtil.processCommonSearchKeywords(queryWrapper, VmMonitor.class, commonElementListDto.getKeywords());
        }
        if (StringUtils.isNotBlank(commonElementListDto.getPId())) {
            queryWrapper = AnnotationUtil.processCommonSearchAnd(queryWrapper, VmMonitor.class, commonElementListDto.getPId());
        }
        List<String> ids = layerElementService.getElementIdsByLayerIdOrType(commonElementListDto.getLayerId(), commonElementListDto.getElementType());
        queryWrapper.notIn(!ids.isEmpty(), "id", ids);
        Page<VmMonitor> page = new Page<>(commonElementListDto.getPageNo(), commonElementListDto.getPageSize());
        return this.page(page, queryWrapper);
    }

    @Override
    public List<?> baseList(CommonElementListDto commonElementListDto) {
        QueryWrapper<VmMonitor> queryWrapper = new QueryWrapper<>();
        ;
        try {
            if (StringUtils.isNotBlank(commonElementListDto.getKeywords())) {
                queryWrapper = AnnotationUtil.processCommonSearchKeywords(queryWrapper, VmMonitor.class, commonElementListDto.getKeywords());
            }
            if (StringUtils.isNotBlank(commonElementListDto.getPId())) {
                queryWrapper = AnnotationUtil.processCommonSearchAnd(queryWrapper, VmMonitor.class, commonElementListDto.getPId());
            }
            return this.list(queryWrapper);
        } catch (Exception e) {
            log.error(e.getMessage());
            throw new RuntimeException(e);
        }
    }

    @Override
    public List<?> baseList(QueryElementDto queryElementDto) {
        QueryWrapper<VmMonitor> queryWrapper = new QueryWrapper<>();
        try {
            if (StringUtils.isNotBlank(queryElementDto.getKeywords())) {
                queryWrapper = AnnotationUtil.processCommonSearchKeywords(queryWrapper, VmMonitor.class, queryElementDto.getKeywords());
            }
            if (queryElementDto.getElementIds() != null && !queryElementDto.getElementIds().isEmpty()) {
                queryWrapper.in("id", queryElementDto.getElementIds());
            }
            if (StringUtils.isNotBlank(queryElementDto.getPId())) {
                queryWrapper = AnnotationUtil.processCommonSearchAnd(queryWrapper, VmMonitor.class, queryElementDto.getPId());
            }
            return this.list(queryWrapper);
        } catch (Exception e) {
            log.error(e.getMessage());
            throw new RuntimeException(e);
        }
    }

    @Override
    public Object getObjectById(String id) {
        return this.getById(id);
    }

    @Override
    public Result<?> setAngleView(String id, String angleView) {
        VmMonitor vmMonitor = this.getById(id);
        if (vmMonitor == null) {
            return Result.error("数据不存在，请刷新重试！");
        }
        vmMonitor.setAngleView(angleView);
        if (this.updateById(vmMonitor)) {
            return Result.ok("更新成功！");
        } else {
            return Result.error("更新失败！");
        }
    }

}
